#include "monitor.h"

#include "exception.h"
#include "util.h"
#include <assert.h>
#include <errno.h>
#include <iostream>
#include <pthread.h>

namespace CThread
{

/**
 * Monitor implementation using the POSIX pthread library
 *
 * @version $Id:$
 */

Monitor::Monitor() 
{
	pthread_mutex_init(&pthread_mutex_, NULL);
	pthread_cond_init(&pthread_cond_, NULL);
}

Monitor::~Monitor() 
{ 
	int iRet = pthread_mutex_destroy(&pthread_mutex_);
    assert(iRet == 0);
	
	iRet = pthread_cond_destroy(&pthread_cond_);
    assert(iRet == 0);
}

void Monitor::lock() 
{
	pthread_mutex_lock(&pthread_mutex_);
}

void Monitor::unlock()
{
	pthread_mutex_unlock(&pthread_mutex_); 
}

void Monitor::wait(int64_t timeout)
{
    // XXX Need to assert that caller owns mutex
    assert(timeout >= 0LL);
	
    if (timeout == 0LL) 
	{
		int iret = pthread_cond_wait(&pthread_cond_, &pthread_mutex_);
		assert(iret == 0);
    } 
	else
	{
		struct timespec abstime;
		int64_t now = Util::currentTime();
		Util::toTimespec(abstime, now + timeout);
		int result = pthread_cond_timedwait(&pthread_cond_, &pthread_mutex_, &abstime);
		if (result == ETIMEDOUT)
		{
			// pthread_cond_timedwait has been observed to return early on
			// various platforms, so comment out this assert.
			//assert(Util::currentTime() >= (now + timeout));
			throw TimedOutException();
		}
    }
}

void Monitor::notify() 
{
    // XXX Need to assert that caller owns mutex
    int iret = pthread_cond_signal(&pthread_cond_);
    assert(iret == 0);
}

void Monitor::notifyAll()
{
    // XXX Need to assert that caller owns mutex
    int iret = pthread_cond_broadcast(&pthread_cond_);
    assert(iret == 0);
}

};
